#!/usr/bin/env node

import crypto from "crypto";
import fs from "fs";
import path, { dirname } from "path";
import readline from "readline";
import chalk from "chalk";
import figlet from "figlet";
import { fileURLToPath } from "url";
import { exec } from "child_process";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

// 定义加密算法、密钥和初始化向量
const algorithm = "aes-256-cbc";
let key = crypto.randomBytes(32);
let iv = crypto.randomBytes(16);

// 创建读取用户输入的接口
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});

let preDir;

// 创建工具函数，处理加密和解密
const cryptoUtils = {
  encrypt(buffer) {
    const cipher = crypto.createCipheriv(algorithm, key, iv);
    return Buffer.concat([cipher.update(buffer), cipher.final()]);
  },
  decrypt(buffer, keyBuffer, ivBuffer) {
    const decipher = crypto.createDecipheriv(algorithm, keyBuffer, ivBuffer);
    return Buffer.concat([decipher.update(buffer), decipher.final()]);
  },
};

// 创建文件操作函数
const fileUtils = {
  checkDirectoryExistence(directory) {
    if (!fs.existsSync(directory)) {
      console.log(`${directory} 文件夹不存在`);
      return false;
    }
    return true;
  },
  ensureDirectoryExistence(directory) {
    if (!fs.existsSync(directory)) {
      fs.mkdirSync(directory);
      console.log(chalk.green(`${directory} 文件夹已创建完成`));
    }
  },
  encryptFile(filepath) {
    const fileContent = fs.readFileSync(filepath);
    const encryptedContent = cryptoUtils.encrypt(fileContent);
    fs.writeFileSync(filepath + ".enc", encryptedContent);
    console.log(`文件已加密: ${filepath} -> ${filepath}.enc`);
    fs.unlinkSync(filepath);
  },
  decryptFile(filepath, keyBuffer, ivBuffer) {
    const encryptedContent = fs.readFileSync(filepath);
    const decryptedContent = cryptoUtils.decrypt(
      encryptedContent,
      keyBuffer,
      ivBuffer
    );
    fs.writeFileSync(filepath.replace(".enc", ""), decryptedContent);
    console.log(`文件已解密: ${filepath} -> ${filepath.replace(".enc", "")}`);
    fs.unlinkSync(filepath);
  },
  encryptAllFilesInDirectory(directory) {
    if (!this.checkDirectoryExistence(directory)) return;
    const files = fs.readdirSync(directory);
    files.forEach((file) => {
      const filepath = path.join(directory, file);
      const stats = fs.lstatSync(filepath);
      if (stats.isDirectory()) {
        this.encryptAllFilesInDirectory(filepath); // 递归处理子目录
      } else if (!filepath.endsWith(".enc")) {
        this.encryptFile(filepath);
      }
    });
    fs.writeFileSync(
      "encryption-key.json",
      JSON.stringify({
        key: key.toString("hex"),
        iv: iv.toString("hex"),
      })
    );
    console.log("密钥和IV已保存到 encryption-key.json");
  },
  decryptAllEncryptedFilesInDirectory(directory) {
    if (!this.checkDirectoryExistence(directory)) return;
    const { key: storedKey, iv: storedIv } = JSON.parse(
      fs.readFileSync("encryption-key.json", "utf8")
    );
    const keyBuffer = Buffer.from(storedKey, "hex");
    const ivBuffer = Buffer.from(storedIv, "hex");
    const files = fs.readdirSync(directory);
    files.forEach((file) => {
      const filepath = path.join(directory, file);
      const stats = fs.lstatSync(filepath);
      if (stats.isDirectory()) {
        this.decryptAllEncryptedFilesInDirectory(filepath); // 递归处理子目录
      } else if (filepath.endsWith(".enc")) {
        this.decryptFile(filepath, keyBuffer, ivBuffer);
      }
    });
  },
  checkFileStatus(directory) {
    if (!this.checkDirectoryExistence(directory)) return "目录不存在";
    const files = fs.readdirSync(directory);
    let normalCount = 0;
    let encCount = 0;
    files.forEach((file) => {
      const filepath = path.join(directory, file);
      const stats = fs.lstatSync(filepath);
      if (stats.isDirectory()) {
        const subStatus = this.checkFileStatus(filepath);
        if (subStatus === "加密") {
          encCount++;
        } else if (subStatus === "未加密") {
          normalCount++;
        }
      } else if (file.endsWith(".enc")) {
        encCount++;
      } else {
        normalCount++;
      }
    });
    if (encCount > 0 && normalCount === 0) {
      return "加密";
    } else if (normalCount > 0 && encCount === 0) {
      return "未加密";
    } else {
      return "部分加密";
    }
  },
  viewFileContent(currentDirectory) {
    if (!this.checkDirectoryExistence(currentDirectory)) return;
    const files = fs.readdirSync(currentDirectory);
    if (files.length === 0) {
      console.log(chalk.green("没有文件，请按 Enter 键继续"));
      rl.question("", () => {
        this.viewFileContent(preDir); // 返回菜单
      });
      return;
    }

    console.log("\n当前目录中的文件和文件夹:");
    files.forEach((file, index) => {
      const filepath = path.join(currentDirectory, file);
      const stats = fs.lstatSync(filepath);
      if (stats.isDirectory()) {
        console.log(`${index + 1}. ${chalk.blue(file)} (文件夹)`);
      } else {
        console.log(`${index + 1}. ${file}`);
      }
    });

    rl.question(
      "请输入要查看的文件或文件夹编号或者按q回到上一级文件夹: ",
      (fileNumber) => {
        console.log("fileNumber", fileNumber);
        if (fileNumber === "q") {
          // 返回上一级文件夹
          let parentDir = path.dirname(currentDirectory);
          if (parentDir === __dirname) {
            showMenu(); // 如果已经是顶级目录，则显示菜单
          } else {
            this.viewFileContent(parentDir); // 否则显示上一级文件夹内容
          }
          return;
        }

        const fileIndex = parseInt(fileNumber.trim(), 10) - 1;
        if (fileIndex >= 0 && fileIndex < files.length) {
          const filepath = path.join(currentDirectory, files[fileIndex]);
          const stats = fs.lstatSync(filepath);
          if (stats.isDirectory()) {
            // 如果是目录，则递归显示目录内容
            this.viewFileContent(filepath);
          } else {
            // 如果是文件，则在外部打开
            if (process.platform === "win32") {
              exec(`start "" "${filepath}"`);
            } else if (process.platform === "darwin") {
              exec(`open "${filepath}"`);
            } else if (process.platform === "linux") {
              exec(`xdg-open "${filepath}"`);
            }
            console.log(`正在外部打开文件: ${filepath}`);
            rl.question("按 Enter 键继续...", () => {
              this.viewFileContent(currentDirectory);
            });
          }
        } else {
          console.log("无效的文件编号，请重试。");
          this.viewFileContent(currentDirectory);
        }
      }
    );
  },
  createFileAndWriteContent(directory) {
    this.ensureDirectoryExistence(directory);
    rl.question("请输入要创建的文件名: ", (filename) => {
      const filepath = path.join(directory, filename);
      rl.question("请输入要写入文件的内容: ", (content) => {
        fs.writeFileSync(filepath, content, "utf8");
        console.log(`文件已创建并写入内容: ${filepath}`);
        this.viewFileContent(directory); // 写入内容后返回当前目录内容
      });
    });
  },
  deleteFile(directory) {
    if (!this.checkDirectoryExistence(directory)) return;
    const files = fs.readdirSync(directory);
    if (files.length === 0) {
      console.log(chalk.green("没有文件，请按 Enter 键继续"));
      rl.question("", () => {
        this.viewFileContent(directory); // 返回当前目录内容
      });
      return;
    }

    console.log("\n当前目录中的文件和文件夹:");
    files.forEach((file, index) => {
      const filepath = path.join(directory, file);
      const stats = fs.lstatSync(filepath);
      if (stats.isDirectory()) {
        console.log(`${index + 1}. ${chalk.blue(file)} (文件夹)`);
      } else {
        console.log(`${index + 1}. ${file}`);
      }
    });

    rl.question("请输入要删除的文件或文件夹编号: ", (fileNumber) => {
      const fileIndex = parseInt(fileNumber.trim(), 10) - 1;
      if (fileIndex >= 0 && fileIndex < files.length) {
        const filepath = path.join(directory, files[fileIndex]);
        const stats = fs.lstatSync(filepath);
        if (stats.isDirectory()) {
          fs.rmdirSync(filepath, { recursive: true });
          console.log(`文件夹已删除: ${filepath}`);
        } else {
          fs.unlinkSync(filepath);
          console.log(`文件已删除: ${filepath}`);
        }
      } else {
        console.log("无效的文件编号，请重试。");
      }
      this.viewFileContent(directory); // 删除文件后返回当前目录内容
    });
  },
};

// 显示ASCII艺术Logo
function showLogo() {
  console.clear();

  console.log(
    chalk.blue(
      figlet.textSync("ENCRYPTION-V-2", {
        font: "Slant",
        horizontalLayout: "default",
        verticalLayout: "default",
      })
    )
  );

  // 显示作者和更新时间
  console.log(chalk.green("作者: ly"));
  console.log(chalk.green("更新时间: 2024-09-10"));
}

// 执行加密操作
function handleEncryptOption() {
  console.log("执行加密操作...");
  const targetDirectory = path.join(__dirname, "file_package");
  fileUtils.ensureDirectoryExistence(targetDirectory);
  const fileStatus = fileUtils.checkFileStatus(targetDirectory);
  if (fileStatus === "加密") {
    console.log("文件已加密，先进行解密...");
    fileUtils.decryptAllEncryptedFilesInDirectory(targetDirectory);
  }
  fileUtils.encryptAllFilesInDirectory(targetDirectory);
  showMenu(); // 执行完操作后更新菜单状态
}

// 执行解密操作
function handleDecryptOption() {
  console.log("执行解密操作...");
  const targetDirectory = path.join(__dirname, "file_package");
  fileUtils.ensureDirectoryExistence(targetDirectory);
  fileUtils.decryptAllEncryptedFilesInDirectory(targetDirectory);
  showMenu(); // 执行完操作后更新菜单状态
}
// 执行查看文件内容操作
function handleViewFilesOption() {
  console.log("查看文件内容...");
  const targetDirectory = path.join(__dirname, "file_package");
  preDir = targetDirectory;
  fileUtils.ensureDirectoryExistence(targetDirectory);
  fileUtils.viewFileContent(targetDirectory);
}

// 执行创建文件并写入内容操作
function handleCreateFileOption() {
  console.log("创建文件并写入内容...");
  const targetDirectory = path.join(__dirname, "file_package");
  fileUtils.ensureDirectoryExistence(targetDirectory);
  fileUtils.createFileAndWriteContent(targetDirectory);
}

// 执行删除文件操作
function handleDeleteFileOption() {
  console.log("删除文件...");
  const targetDirectory = path.join(__dirname, "file_package");
  fileUtils.ensureDirectoryExistence(targetDirectory);
  fileUtils.deleteFile(targetDirectory);
}

// 显示菜单并等待用户输入
function showMenu() {
  showLogo();
  const targetDirectory = path.join(__dirname, "file_package");
  const status = fileUtils.checkFileStatus(targetDirectory);
  let statusText;

  if (status === "加密") {
    statusText = chalk.red(status);
  } else if (status === "未加密") {
    statusText = chalk.green(status);
  } else {
    statusText = status;
  }

  console.log(`\n当前文件状态: ${statusText}`);
  console.log("请选择一个操作:");
  console.log("1. 加密");
  console.log("2. 解密");
  console.log("3. 查看文件内容");
  console.log("4. 创建文件并写入内容");
  console.log("5. 删除文件");
  console.log("q. 退出");
  rl.question("请输入编号: ", handleUserInput);
}

// 处理用户输入
function handleUserInput(input) {
  switch (input.trim()) {
    case "1":
      handleEncryptOption();
      break;
    case "2":
      handleDecryptOption();
      break;
    case "3":
      handleViewFilesOption();
      break;
    case "4":
      handleCreateFileOption();
      break;
    case "5":
      handleDeleteFileOption();
      break;
    case "q":
      rl.close();
      return;
    default:
      console.log("无效的选择，请重试。");
      showMenu(); // 输入无效时重新显示菜单
  }
}

// 当接口关闭时执行的操作
rl.on("close", () => {
  console.log("程序已退出");
  process.exit(0);
});

// 显示菜单初始调用
showMenu();
